using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;

namespace StupidSpaceThing
{

	public enum Action { Click, Down, Up };	
	public delegate void KeyHandler(Keys key, Action action, RealGameTime gameTime);
	public delegate void ButtonHandler(Buttons button, Action action, PlayerIndex index, RealGameTime gameTime);

	internal static class RealInput
	{	
		private static List<KeyListener> keyListeners = new List<KeyListener>();
		private static Queue<KeyListener> keyListenerQueue = new Queue<KeyListener>();
		private static List<ButtonListener> buttonListeners = new List<ButtonListener>();
		private static Queue<ButtonListener> buttonListenerQueue = new Queue<ButtonListener>();
		private static PlayerIndex[] gamePadIndices = { PlayerIndex.One, PlayerIndex.Two, PlayerIndex.Three, PlayerIndex.Four };

		public static void Update(RealGameTime gameTime) {
			while( keyListenerQueue.Count > 0 ) {
				keyListeners.Add(keyListenerQueue.Dequeue());
			}
			KeyboardState keyboardState = Keyboard.GetState();
			foreach( KeyListener listener in keyListeners ) {
				listener.Update(keyboardState, gameTime);
			}
			while( buttonListenerQueue.Count > 0 ) {
				buttonListeners.Add(buttonListenerQueue.Dequeue());
			}
			foreach( PlayerIndex index in gamePadIndices ) {
				GamePadState gamePadState = GamePad.GetState(Microsoft.Xna.Framework.PlayerIndex.One);
				if( !gamePadState.IsConnected ) {
					continue;
				}
				foreach( ButtonListener listener in buttonListeners ) {
					listener.Update(gamePadState, index, gameTime);
				}
			}
		}

		public static void Listen(Keys key, KeyHandler handler) {
			keyListenerQueue.Enqueue(new KeyListener(key, handler));
		}

		public static void Listen(Buttons button, ButtonHandler handler) {
			buttonListenerQueue.Enqueue(new ButtonListener(button, handler));
		}

		private class KeyListener
		{
			public readonly Keys Key;
			public readonly KeyHandler Handler;
			private bool down = false;

			public KeyListener(Keys key, KeyHandler handler) {
				this.Key = key;
				this.Handler = handler;
			}

			public void Update(KeyboardState keyboardState, RealGameTime gameTime) {				
				bool isDownNow = keyboardState.IsKeyDown(Key);
				if( isDownNow == down ) {
					return;
				}
				if( isDownNow ) {
					Handler.Invoke(Key, Action.Down, gameTime);
				} else {
					Handler.Invoke(Key, Action.Up, gameTime);
				}
				if( down != isDownNow && !isDownNow ) {
					Handler.Invoke(Key, Action.Click, gameTime);
				}
				down = isDownNow;
			}
		}

		private class ButtonListener
		{
			public readonly Buttons Button;
			public readonly ButtonHandler Handler;
			private bool down = false;

			public ButtonListener(Buttons button, ButtonHandler handler) {
				this.Button = button;
				this.Handler = handler;
			}

			public void Update(GamePadState gamePadState, PlayerIndex index, RealGameTime gameTime) {
				bool isDownNow = gamePadState.IsButtonDown(Button);
				if( isDownNow == down ) {
					return;
				}
				if( isDownNow ) {
					Handler.Invoke(Button, Action.Down, index, gameTime);
				} else {
					Handler.Invoke(Button, Action.Up, index, gameTime);
				}
				if( down != isDownNow && !isDownNow ) {
					Handler.Invoke(Button, Action.Click, index, gameTime);
				}
				down = isDownNow;
			}
		}
	}
}
